package cn.monkey.state.scheduler;


import cn.monkey.state.scheduler.strategy.WaitingStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadFactory;

public class SimpleEventPublishScheduler extends EventLoopScheduler implements EventPublishScheduler {
    private static final Logger log = LoggerFactory.getLogger(SimpleEventPublishScheduler.class);
    protected final BlockingQueue<Runnable> taskQueue;

    public SimpleEventPublishScheduler(long id, WaitingStrategy waitingStrategy, ThreadFactory threadFactory) {
        super(id, waitingStrategy, threadFactory);
        this.taskQueue = new ArrayBlockingQueue<>(1024);
    }

    @Override
    protected final void execute() {
        if (this.taskQueue.isEmpty()) {
            return;
        }
        int size = this.taskQueue.size();
        List<Runnable> list = new ArrayList<>(size);
        this.taskQueue.drainTo(list, size);
        for (Runnable r : list) {
            try {
                r.run();
            } catch (Throwable throwable) {
                log.error("task execute error:\n", throwable);
            }
        }
    }

    @Override
    public void publish(Runnable r) {
        if (this.taskQueue.offer(r)) {
            this.waitingStrategy.signalAllWhenBlocking();
            return;
        }
        if (log.isDebugEnabled()) {
            log.debug("id: {}'s taskQueue is full, run event directly", this.id());
        }
        r.run();
    }
}
